﻿///////////////////////////////////////////////////////////////////////////////
// File:        Socket.hpp
// Author:      671643387@qq.com
// Date:        2016年1月5日 下午5:43:21
// Description:
///////////////////////////////////////////////////////////////////////////////

#ifndef NET_SOCKET_HPP_
#define NET_SOCKET_HPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <event2/event.h>
#include <deque>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
#include <fog/Typedef.hpp>
#include <fog/util/CircleBuffer.hpp>
#include <fog/util/MessageBlock.hpp>
#include <fog/thread/LockGuard.hpp>
#include <fog/thread/Mutex.hpp>

namespace fog
{
    namespace net
    {
        class SocketThread;
        class SocketManager;

        class Socket : public boost::noncopyable
        {
        public:
            Socket(void);
            ~Socket(void);

        public:
            bool open(evutil_socket_t s, SocketThread *t);
            void close(void);

            int getId(void) const { return id_; }
            std::string getPeerAddr(void);
            int getPeerPort(void);

        public:
            std::size_t recv_size(void) { return recvBuff_.size(); }
            std::size_t recv(BYTE_t *buf, std::size_t len) { return recvBuff_.read(buf, len); }
            std::size_t recv_peek(BYTE_t *buf, std::size_t len) { return recvBuff_.peek(buf, len); }
            std::size_t recv_skip(std::size_t len) { return recvBuff_.skip(len); }

        public:
            void send(const BYTE_t *buf, std::size_t len);

        public:
            static bool setnonblocking(evutil_socket_t s);
            static void close(evutil_socket_t s);

        protected:
            virtual void onOpen(void);
            virtual void onRecv(void);
            virtual void onClose(void);

        private:
            int recv_net(BYTE_t *buf, int len);
            int send_net(const BYTE_t *buf, int len);

            bool notifySend(void);
            void trySend(util::MessageBlock *mb);

        private:
            void doClose(void);

        private:
            void doRecv(void);
            static void onRecv(evutil_socket_t sock, short event, void* arg);
            void doSend(void);
            static void onSend(evutil_socket_t sock, short event, void* arg);

        private:
            friend class SocketManager;

        private:
            typedef std::deque<util::MessageBlockPtr>   MessageQueue;

        private:
            int id_;
            SocketManager *owner_;
            SocketThread *actor_;
            evutil_socket_t sock_;
            struct event *evRecv_;
            struct event *evSend_;
            struct event_base *evBase_;
            struct sockaddr_in addr_;

            util::CircleBuffer recvBuff_;
            MessageQueue msgQueue_;
            thread::Mutex msgQueueLock_;
            bool sendPending_;
            thread::Mutex sendPendingLOCK_;
        };

        typedef boost::shared_ptr<Socket>   SocketPtr;
    }
}

#endif /* NET_SOCKET_HPP_ */
